(({config,CONST} = vinculum)=>{
	class helper {
		extend(a = {},b = {}){
			for(let key in b){
				if(b.hasOwnProperty(key)){
					a[key] = b[key];
				}
			}
			return a;
		}
		
		setCookie(sName, sValue, nDays){
			let expires = "";
			if (typeof nDays === "number"){
				var d = new Date();
				d.setTime(d.getTime() + nDays * 24 * 60 * 60 * 1000);
				expires = "; expires=" + d.toGMTString();
			}

			document.cookie = sName + "=" + escape(sValue) + expires + "; path=/";
		}
		
		getCookie(sName) {
			let re = new RegExp("(\;|^)[^;]*(" + sName + ")\=([^;]*)(;|$)");
			let res = re.exec(document.cookie);
			return res != null ? unescape(res[3]) : null;
		}
		
		removeCookie(name) {
			this.setCookie(name, "", -1);
		}
		
		uuid32(){
			return this._uuid('xxxxxxxxxxxxxxxxyxxxxxxxxxxxxxxx');
		}
		
		uuid16(){
			return this._uuid('xxxxxxxxxyxxxxxx');
		}
		
		_uuid(str1){
			let str2 = str1.replace(/[xy]/g,function(c){
				let r = Math.random()*16 | 0;
				let v = (c == 'x' ? r : (r&0x3| 0x8));
				return v.toString(16);
			});
			return str2;
		}
		
		trim(a){
			if(typeof a != 'string') return '';
			return a.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g,'');
		}
		
		isIE(){
			return navigator.userAgent.match(/(?:MSIE |Trident.*rv:)(\d+)|$/i)[1],isWebkit=/webkit/i.test(navigator.userAgent),isWindows=/Windows NT/.test(navigator.userAgent);
		}
		
		isMobile(){
			return this.hasTouch();
		}
		
		isAndroid(){
			return navigator.userAgent.indexOf('Android') > 0;
		}
		
		isIOS(){
			return /iP(ad|hone|od)/.test(navigator.userAgent);
		}
		
		hasTouch(){
			return this.isAndroid() || this.isIOS();
		}
		
		params2json(s){
			let ret = {};
			if(s && typeof s === 'string'){
				let arr1 = s.replace(/^\?/g,'').split('&');
				if(arr1 && arr1.length){
					for(let i=0,len=arr1.length;i<len;i++){
						let arr2 = arr1[i]?arr1[i].split('='):[];
						if(arr2 && arr2.length && arr2.length ===2){
								ret[arr2[0]] = arr2[1];
						}
					}
				}
			}
			return ret;
		}
		
		json2params(o){
			let ret = '';
			if(typeof o === 'object'){
				let arr1 = [];
				for(let key in o){
					if(o.hasOwnProperty(key)){
						arr1.push(key + '=' + encodeURIComponent(o[key]));
					}
				}
				if(arr1.length>0){
					ret = arr1.join('&');
				}
			}
			return ret;
		}
		
		IsURL(str_url){
			let strRegex = '^((https|http|ftp|rtsp|mms)?://)' 
			+ '?(([0-9a-z_!~*\'().&=+$%-]+: )?[0-9a-z_!~*\'().&=+$%-]+@)?' 
			+ '(([0-9]{1,3}.){3}[0-9]{1,3}'
			+ '|' 
			+ '([0-9a-z_!~*\'()-]+.)*' 
			+ '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].' 
			+ '[a-z]{2,6})'
			+ '(:[0-9]{1,4})?'
			+ '((/?)|' 
			+ '(/[0-9a-z_!~*\'().;?:@&=+$,%#-]+)+/?)$'; 
			let re=new RegExp(strRegex); 
			return re.test(str_url);  
		}
		
		parseURL(str_url){
			if(this.IsURL(str_url)){
				let a = document.createElement('a');
				a.href = str_url;
				let o1 = {
					source:str_url
					,protocol:a.protocol.replace(':','')
					,host:a.hostname
					,port:a.port||80
					,query:a.search
					,params:(function(){
						let ret = {}
						,seg=a.search.replace(/^\?/,'').split('&')
						,len=seg.length,i=0,s;
						for(;i<len;i++){
							if(!seg[i]){
									continue;
							}
							s = seg[i].split('=');
							ret[s[0]] = s[1];
						}
						return ret;
					})()
					,file:(a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1]
					,hash:a.hash.replace('#','')
					,path:a.pathname.replace(/^([^\/])/,'/$1')
					,relative:(a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1]
					,segments:a.pathname.replace(/^\//,'').split('/')
				};
				return o1;
			}else{
				return null;
			}
		}
		
		_getXMLHttp(){
			let xmlHttp;
			if (window.XMLHttpRequest) {
				xmlHttp=new XMLHttpRequest();
			}else if (window.ActiveXObject){
				xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
			}
			return xmlHttp;
		}
		
		ajax(option){
			let xmlHttp = this._getXMLHttp();
			let async = true;
			if(option.async === false) async = false;
			if(!xmlHttp){
					option.fail("don't support XMLHttp!");
			}else{
				let defaultOption = {
					method:'GET'
				};
				this.extend(defaultOption,option);
				xmlHttp.onreadystatechange=function(){
					if (xmlHttp.readyState == 4){
						if(xmlHttp.status == 200){
							let ret;
							try{
								ret = JSON.parse(xmlHttp.responseText);
							}catch(e){
								ret = xmlHttp.responseText;
							}
							defaultOption.success(ret);
						}else{
							defaultOption.fail(xmlHttp.status,xmlHttp.statusText,xmlHttp.responseText);
						}
					}
				}
				if(defaultOption.method === 'GET' && defaultOption.params){
					let prefix = '?';
					if(defaultOption.url.indexOf('?')>0){
						prefix = '&';
					}
					defaultOption.url = defaultOption.url + prefix + defaultOption.params;
				}
				xmlHttp.open(defaultOption.method,defaultOption.url,async);
				if(defaultOption.method === 'POST'){
					xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
					xmlHttp.send(defaultOption.params);
				}else{
					xmlHttp.send(null);
				}
			}
		}
	}
	
  vinculum.helper = new helper();

	vinculum.helper.REG = {
		NUMBER:/^[0-9]+$/
		,MOBILE:/^1[34578][0-9]{9}$/
		,CARD15:/^([1-9]\d{5})(\d{2})(0[1-9]|10|11|12)([0-2][1-9]|10|20|30|31)(\d{3})$/
		,CARD18:/^([1-9]\d{5})((19|20|21)\d{2})(0[1-9]|10|11|12)([0-2][1-9]|10|20|30|31)(\d{3}[0-9Xx])$/
		,URL: /((http|ftp|https):\/\/)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(\/[a-zA-Z0-9\&%_\.\/-~-]*)?/i
	};
	
	vinculum.helper.card = {
		validLast:function (str){
			return vinculum.helper.getValid(str) === str[str.length-1];
		}
		,getValid:function (str){
			let m = 0
			let co=[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2];
			let verCode=['1','0','X','9','8','7','6','5','4','3','2'];
			for (let i = 0; i < str.length-1; i++) {
					m+=parseInt(str[i])*co[i];
			}
			let residue=m%11;
			return verCode[residue];
		}
		,card15To18:function (str){
			if(!vinculum.helper.REG.REGCARD15.test(str)) return str;
			let strs = str.split(vinculum.helper.REG.REGCARD15);
			let year = parseInt(strs[2]);
			let nowyear = new Date().getFullYear() % 100;
			let beforeyear = '20';
			if(year > nowyear) beforeyear = '19';
			strs.splice(2,0,beforeyear);
			let card18 = strs.slice(0,7).join('');
			card18 += vinculum.helper.getValid(card18 + '0');
			return card18;
		}
		,getCardInfo:function (str){
			let card = vinculum.helper.card15To18(str);
			if(vinculum.helper.REG.REGCARD18.test(card)){
				let cards = card.split(vinculum.helper.REG.REGCARD18);
				cards.splice(3,1);
				console.log(cards);
				let result = {
					area: cards[1]
					,sex: (parseInt(cards[5]) % 2 === 0? '女':'男')
					,birthday: cards.slice(2,5).join('-')
				};
				return result;
			}
		}
	};
})(vinculum);

(({config,helper,CONST} = vinculum)=>{
	class server {
		constructor(action_path,service_path){
			this.actionPath = action_path;
			this.servicePath = service_path;
		}
		
		_connect(url, params, method,async){
			let reto = {};
			let option = {
					url : url,
					method : method || 'GET',
					params : helper.json2params(params),
					async:async,
					success:function(retdata){
						reto.code = 200;
						reto.data = retdata;
					}
					,fail:function(status,statusText,responseText){
						reto = {code:status,msg:responseText,status:statusText};
					}
			};
			if(async === false){
				helper.ajax(option);
				return reto;
			}else{
				return new ES6Promise.Promise(function(resolve, reject){
					option.success = function(retdata){
						resolve(retdata);
					};
					option.fail = function(status,statusText,responseText){
						reject({code:status,msg:responseText,status:statusText});
					};
					helper.ajax(option);
				});
			}
    }
		
		catchFun(err){
			if(err.code){
				if(err.code === 599){
					alert(err.msg);
				}else{
					alert(err.status);
				}
			}else{
				alert(err);
			}
		}
		
		invokeAction(name,params,async){
      let self = this;
			let path = self.actionPath + name;
			return self._connect(path,params,'POST',async);
    }
		
		invokeService(name,params,async){
      let self = this;
			let path = self.servicePath + name;
			return self._connect(path,params,'POST',async);
    }
	}
	vinculum.server = new server(config.actionPath,config.servicePath);
})(vinculum);

(({config,helper,CONST} = vinculum)=>{
	let __components = {};
  let __theme = 'default';
  vinculum.components = {
		create:function(a,b,c){
			let children = [];
			for(let i=3,len=arguments.length;i<len;i++){
				children.push(arguments[i]);
			}
			if(! __components[__theme]){
				throw 'not found theme: ' + __theme;
			}
			return __components[__theme][a][b].apply(null,[c].concat(children));
		}
    ,createBase:function(name,option){
			let children = [];
			for(let i=2,len=arguments.length;i<len;i++){
				children.push(arguments[i]);
			}
      return this.create.apply(this,['base',name,option].concat(children));
    }
		,createController:function(name,option){
			let children = [];
			for(let i=2,len=arguments.length;i<len;i++){
				children.push(arguments[i]);
			}
      return this.create.apply(this,['controller',name,option].concat(children));
		}
		,setTheme:function(themname){
			__theme = themname;
		}
		,registTheme:function(themname,obj){
			__components[themname] = obj;
		}
  };
})(vinculum);